home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / newsgrp / group99a.txt / 000210_icon-group-sender _Thu Oct 7 12:26:03 1999.msg < prev    next >
Internet Message Format  |  2000-09-20  |  10KB

  1. Return-Path: <icon-group-sender>
  2. Received: (from root@localhost)
  3.     by baskerville.CS.Arizona.EDU (8.9.1a/8.9.1) id MAA28331
  4.     for icon-group-addresses; Thu, 7 Oct 1999 12:25:00 -0700 (MST)
  5. Message-Id: <199910071925.MAA28331@baskerville.CS.Arizona.EDU>
  6. Date: Thu, 07 Oct 1999 09:33:25 -0700
  7. From: Steve Wampler <swampler@noao.edu>
  8. X-Accept-Language: en
  9. To: icon-group@optima.CS.Arizona.EDU
  10. CC: Steve Wampler <sbw@tapestry.tucson.az.us>
  11. Subject: Re: A small puzzle
  12. Errors-To: icon-group-errors@optima.CS.Arizona.EDU
  13. Status: RO
  14.  
  15. This is a multi-part message in MIME format.
  16. --------------D3D91CF3B7EB1333F3CB751F
  17. Content-Type: text/plain; charset=us-ascii
  18. Content-Transfer-Encoding: 7bit
  19.  
  20. Steve Wampler wrote:
  21. >    Write an Icon program to generate the pairings in a round-robin
  22. >    tournament.  The program should accept the player names as
  23. >    command line arguments (see the example below).
  24.  
  25. Ok, I don't think anyone else is going to submit a response, so here's
  26. a quick summary.  Two people submitted working solutions - Gregg Townsend
  27. and Andru Luvisi.  Andru's solution needs a (very) minor modification
  28. to meet the requirement of using names from the command-line arguments,
  29. but that's a pretty trivial change (I've made it in the attachment).
  30. Gregg's solution is pretty interesting, it's crafted from scratch and
  31. uses a mapping to single characters to allow string scanning and cset
  32. operations - it's also the best-commented.  The use of csets limits
  33. the tournament to at most 255 players, which is probably ok in most
  34. real-world situations.  Gregg's solution is also attached.
  35.  
  36. One person gave a nice graph-theory-based analysis of the problem
  37. with an algorithm for the solution, but without actual code.  The
  38. analysis is good, though the algorithm is mildly wasteful of space.
  39. (I won't repost the algorithm here since it has already shown up in
  40. this group, but you might take a look at it and see if you can
  41. identify the wasted space...).
  42.  
  43. No one tried either of the two challenges: (a) add an option to
  44. specify the number of 'real' courts and (b) arrange the ordering
  45. so the last round pairs players in the same order they appear on
  46. the command line.  It's probably just as well that no one did (a),
  47. as Andru pointed out, the ugliness is when the number of courts
  48. exceeds the number of players. I've included in my code a solution to
  49. (b) - the same strategy could be applied to Andru's solution, but
  50. would need a different initial pattern.
  51.  
  52. My code is similar to Andru's, using the same basic algorithm
  53. (which is a varient of the graph-based algorithm already posted.
  54. You might look to see how the use of the space is improved.
  55. Can you figure out how to use still less space?)
  56.  
  57. After seeing how nicely Gregg's code was commented, I went back
  58. and added some comments...
  59.  
  60. ----------------------------------------------------------------
  61. # Generate the pairings for each round of a round-robin tournament.
  62. #
  63. # Usage: roundrobin list-of-players...
  64. #
  65. procedure main(args)
  66.     if *args = 0 then args := ["alice", "bonnie", "carole"]
  67.     doRoundRobin(args)
  68. end
  69.  
  70. # Do the scheduling for the tournament.
  71. #
  72. #   This implementation produces an 'interesting' final round.  If the
  73. #   order of the names given on the command line corresponds to the
  74. #   seeding order for the tournament, then the final round pairs
  75. #   the top two seeds, the next two, and so on.  This should help
  76. #   keep the spectators around, allowing you to make more money
  77. #   on refreshments.  If you don't want this, comment out the line:
  78. #
  79. #     names := reorder(names)
  80. #
  81. procedure doRoundRobin(names)
  82.     # force an even number of contestents
  83.     if *names % 2 = 1 then put(names,"bye")
  84.  
  85.     names := reorder(names)
  86.  
  87.     every outPairs(1 to *names-1, names := adjust(names))
  88. end 
  89.  
  90. # Adjust the list of players for the next round.
  91. #
  92. #   The algorithm is "leave the first alone, rotate the rest one position"
  93. #
  94. procedure adjust(playerList)
  95.     return playerList[1:2] ||| playerList[3:0] ||| playerList[2:3]
  96. end
  97.  
  98. # Display the pairings for a single round.
  99. #
  100. procedure outPairs(i, names)
  101.     write("Round ",i)
  102.     every c := 1 to (*names/2) do {   # pair from edges toward center
  103.         write("\tCourt ", right(c,2), ": ", names[c], " vs ", names[-c])
  104.         }
  105. end
  106.  
  107. # Reorder the names so the first call to adjust() produces an ordering
  108. #   that ensures the final round pairs the players in the original order
  109. #
  110. procedure reorder(names)
  111.     every new := put([], names[(1 to *names by 2) | (*names to 2 by -2)])
  112.     return new
  113. end
  114. -------------------------------------------------------
  115.  
  116. I hope some of you had fun thinking about this problem!
  117. --
  118. Steve Wampler-  SOLIS Project, National Solar Observatory
  119. swampler@noao.edu
  120. --------------D3D91CF3B7EB1333F3CB751F
  121. Content-Type: text/plain; charset=us-ascii;
  122.  name="andru.icn"
  123. Content-Disposition: inline;
  124.  filename="andru.icn"
  125. Content-Transfer-Encoding: 7bit
  126.  
  127. procedure main(args)
  128.  every gameset := turnament(args)
  129.   do every write((left((pair := !gameset)[1], 5) || left(pair[2], 5)) | "");
  130. end
  131.  
  132. procedure turnament(people)
  133.  local i;
  134.  local stationary_player, gameset;
  135.  
  136.  stationary_player := (*people % 2 = 0 & get(people)) | "Buy";
  137.  every 1 to *people do {
  138.    gameset := [ [ stationary_player, people[*people] ] ];
  139.    every gameset |||:= [[people[ i := 1 to (*people - 1) / 2 ], people[-i-1]]];
  140.    suspend gameset;
  141.    push(people, pull(people));
  142.  }
  143.  fail;
  144. end
  145.  
  146. --------------D3D91CF3B7EB1333F3CB751F
  147. Content-Type: text/plain; charset=us-ascii;
  148.  name="gregg.icn"
  149. Content-Disposition: inline;
  150.  filename="gregg.icn"
  151. Content-Transfer-Encoding: 7bit
  152.  
  153. ## rrobin.icn -- generate round-robin pairings
  154. #
  155. #  usage:  rrobin name...
  156. #
  157. #  1-Oct-1999 / gmt  (inspired by a Steve Wampler puzzle challenge)
  158. #  
  159. #  This program generates an optimal set of pairings for a round-robin
  160. #  tournament.  For an even number N of players, N-1 rounds on N/2  
  161. #  courts are needed.  For N odd, N rounds on N/2 courts are required,
  162. #  with a "bye" on an additional "court" at each round.
  163.  
  164. procedure main(args)
  165.    local n, ct, labels, round, name1, name2
  166.    
  167.    if *args > 255 then
  168.       stop("too many names")
  169.    labels := (&cset -- ' ')[1+:*args]
  170.    n := 0
  171.    every round := pairs(labels) do round ? {
  172.       write("Round ", n +:= 1)
  173.       ct := 0
  174.       while =" " do {
  175.          name1 := args[upto(move(1), labels)]
  176.          name2 := args[upto(move(1), labels)]
  177.          write("\tCourt  ", ct +:= 1, ": ", name1, " vs ", name2)
  178.          }
  179.       if name1 := args[upto(labels -- round, labels)] then
  180.          write("\tCourt  ", ct +:= 1, ": bye vs ", name1)
  181.       }
  182. end
  183.  
  184.  
  185. ## pairs(players) -- generate pairings for round-robin tournament
  186. #
  187. #  The characters of the string "players" label contestants to be paired
  188. #  in a round-robin tournament.  This procedure generates an optimal set
  189. #  of rounds such that at the end each player is paired exactly once with
  190. #  each other player.  Characters in "players" must be unique and must not
  191. #  include the space character (' '); thus a maximum of 255 contestants
  192. #  can be handled.
  193. #
  194. #  Output is a sequence of strings where each string represents one
  195. #  round of disjoint pairings.  Each pairing consists of three
  196. #  characters: a space followed by the labels of the two contestants.
  197. #
  198. #  1-Oct-1999 / gmt
  199.  
  200. procedure pairs(players)
  201.    if *players < 2 then
  202.       fail
  203.    else if *players = 2 then
  204.       return " " || players
  205.    else if *players % 2 = 1 then
  206.       suspend oddpairs(players)
  207.    else
  208.       suspend evenpairs(players)
  209. end
  210.  
  211.  
  212.  
  213. ## oddpairs(players) -- generate pairings for an odd number of contestants
  214. #
  215. #  With an odd number N of players, the optimum solution requires N rounds
  216. #  on N/2 courts with one "bye" in each round.  A regular pattern produces
  217. #  the pairings:  Each round pairs 1 vs N, 2 vs N-1, 3 vs N-2, etc.,
  218. #  designating a different player as #1 for each of N rounds.
  219.  
  220. procedure oddpairs(players)
  221.    local n, i, j, round
  222.  
  223.    n := *players
  224.    every i := 1 to n do {
  225.       round := ""
  226.       every j := 1 to n / 2 do
  227.          round ||:= " " || players[j] || players[n - j]
  228.       players := players[2:0] || players[1]
  229.       suspend round
  230.       }
  231. end
  232.  
  233.  
  234.  
  235. ## evenpairs(players) -- generate pairings for an even number of contestants
  236. #
  237. #  With an even number N of players, N-1 rounds on N/2 courts are needed.
  238. #  There are no byes.  First, the players are divided into two groups,
  239. #  and the pairings within each group are enumerated in parallel.  If the
  240. #  groups are odd-sized, there is a bye within each group at each round;
  241. #  the two unoccupied players play each other across group boundaries.
  242. #  After the intra-group competition, the remaining combinations of
  243. #  cross-group pairings are enumerated.
  244.  
  245. procedure evenpairs(players)
  246.    local half, odd, grp1, grp2, p1, p2, round, step, i
  247.  
  248.    half := *players / 2
  249.    odd := half % 2
  250.    grp1 := players[1+:half]
  251.    grp2 := players[0-:half]
  252.  
  253.    every put(p1 := [], pairs(grp1))
  254.    every put(p2 := [], pairs(grp2))
  255.    while round := get(p1) || get(p2) do {
  256.       if odd = 1 then
  257.          round ||:= " " || (players -- round)
  258.       suspend round
  259.    }
  260.  
  261.    grp2 := grp2 || grp2
  262.    every step := odd to half - 1 do {
  263.       round := ""
  264.       every i := 1 to half do
  265.          round ||:= " " || grp1[i] || grp2[i + step]
  266.       suspend round
  267.       }
  268. end   
  269.  
  270.  
  271. --------------D3D91CF3B7EB1333F3CB751F--
  272.  
  273.